// const apiUrl = '/dev/api/extend/Graph/generateDiagnosisKnowledgeGraph'; // Replace with your Neo4j API endpoint URL
const apiUrl = '/dev/api/extend/Graph/queryGraphResult'; // Replace with your Neo4j API endpoint URL
const service = axios.create({
    // baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
    withCredentials: false, // send cookies when cross-domain requests
    // timeout: define.timeout, // request timeout
  })
  // request interceptor
service.interceptors.request.use(
    config => {
        debugger
      if (config.url.indexOf('http') > -1) config.baseURL = ''
      let token = window.localStorage.getItem('jnpf_token')
      config.headers['Authorization'] = token
      if (config.method == 'get') {
        config.params = config.data
      }
      let timestamp = Date.parse(new Date()) / 1000
      if (config.url.indexOf('?') > -1) {
        config.url += `&n=${timestamp}`
      } else {
        config.url += `?n=${timestamp}`
      }
      return config
    },
    error => {
      // do something with request error
      if (process.env.NODE_ENV === 'development') {
        console.log(error) // for debug
      }
      return Promise.reject(error)
    }
  )
// Function to fetch data from Neo4j API using Axios
const fetchData = async () => {
  try {
    let params = {"domain":"故障诊断知识图谱","nodeName":"","pageSize":5000}
    const response = await service.post(apiUrl,params,{
        headers: {
            'Content-Type': 'application/json'
          }
    });
    const data = response.data;
    return data;
  } catch (error) {
    console.error('Error fetching data:', error);
    return null;
  }
};

// Function to create a graph using D3.js
const createGraph = (data) => {

    
  const width = 1000;
  const height = 600;

  const color_rootnode = '#47df06';
  const color_node = '#0410eb';
  const color_fault = '#eb0404';
  const color_processor = '#049aeb';


  // Get the width and height of the window
  const windowWidth = window.innerWidth;
  const windowHeight = window.innerHeight;
  // Calculate the position to center the SVG
  const svgLeft = (windowWidth - width) / 2;
  const svgTop = (windowHeight - height) / 2;

  const svg = d3.select('#visualization')
    .append('svg')
    .attr('width', width)
    .attr('height', height)
    .style('position', 'absolute')
    .style('left', svgLeft + 'px')
    .style('top', svgTop + 'px')
    .call(d3.zoom().scaleExtent([1, 8]).on('zoom', zoomed))
    .append('g');

    debugger
  // Your visualization code here.
  // You can use the 'data' to draw nodes and edges on the SVG canvas.
 
    const simulation = d3.forceSimulation(data.node)
    .force('link', d3.forceLink(data.relationship)
    .id(d => {
        // debugger
        // return d.故障诊断知识图谱_nodeId
        return d.uuid
    }))
    // .force('charge', d3.forceManyBody())
    .force('charge', d3.forceManyBody().strength(350)) // Negative value to repel nodes
    .force('center', d3.forceCenter(width / 2, height / 2))
    .force('collide', d3.forceCollide(60));
    

    const link = svg.append('g')
    .attr('class', 'links')
    .selectAll('line')
    .data(data.relationship)
    .enter()
    .append('line')
    .attr('class', 'link');

    // // Add relationship text to the graph
    // const linkText = svg.append('g')
    //   .attr('class', 'link-text')
    //   .selectAll('text')
    //   .data(data.relationship)
    //   .enter()
    //   .append('text')
    //   .attr('class', 'linktext')
    //   .text(d => {
    //     debugger
    //     return d.name
    //   }) // Display the relationship uuid, you can change it to any other property you want
    //   .attr('text-anchor', 'middle')
    //   .style('fill', 'black');

    // Add relationship text to the graph using foreignObject
    const linkText = svg.append('g')
      .attr('class', 'link-text')
      .selectAll('foreignObject')
      .data(data.relationship)
      .enter()
      .append('foreignObject')
      .attr('width', 80) // Adjust the width to fit the text content
      .attr('height', 20) // Adjust the height to fit the text content
      .attr('class', 'linktext')
      .attr('x', d => (d.source.x + d.target.x) / 2 - 40) // Position the text in the middle of the link
      .attr('y', d => (d.source.y + d.target.y) / 2 - 10) // Position the text in the middle of the link
      .html(d => `
        <xhtml:div style="width: 100%; height: 100%; background-color: white; text-align: center; padding: 2px;">
          ${d.name} <!-- Display the relationship uuid, you can change it to any other property you want -->
        </xhtml:div>
      `);

    const node = svg.append('g')
    .attr('class', 'nodes')
    .selectAll('circle')
    .data(data.node)
    .enter()
    .append('circle')
    .attr('class', 'node')
    .attr('r',  d => {
      let nodeType = d.nodeType
      let r = 25
      let color = color_node
      if(nodeType=='根节点'){
        r = 40
      }else if(nodeType=='节点'){
        r = 30
      }
      return r
  })
    .attr('fill', d => {
        let nodeType = d.nodeType
        let color = color_node
        if(nodeType=='根节点'){
          color = color_rootnode
        }else if(nodeType=='节点'){
            color = color_node
        }else if(nodeType=='故障'){
            color = color_fault
        }else if(nodeType=='操作'){
            color = color_processor
        }
        return color
    }) // Fill the nodes with different colors based on nodeType
    // .attr('stroke','#FFFFFF')
    // .attr('stroke-width', 2) // Set the width of the border
    .attr('style', d => `stroke: #FFF; stroke-width: 2px;`) // Set the border color and widt
    .call(drag(simulation));

    // Add node names as SVG text elements
    const nodeText = svg.append('g')
    .attr('class', 'nodetext')
    .selectAll('text')
    .data(data.node)
    .enter()
    .append('text')
    .attr('dy', 4) // Adjust the vertical position of the text relative to the node center
    .text(d => truncateText(d.name, 4)); // Truncate the text to 10 characters

    node.append('title')
    .text(d => {
        return d.name
    });

    function truncateText(text, maxLength) {
        if (text&&text.length > maxLength) {
          return text.slice(0, maxLength) + '...'; // Truncate and add ellipsis
        }
        return text;
      }


    
    simulation.on('tick', () => {
        link
          .attr('x1', d => d.source.x)
          .attr('y1', d => d.source.y)
          .attr('x2', d => d.target.x)
          .attr('y2', d => d.target.y);
      
        node
          .attr('cx', d => d.x)
          .attr('cy', d => d.y);
      
        // Update the position of node names
        nodeText
          .attr('x', d => d.x)
          .attr('y', d => d.y);

        linkText
        .attr('x', d => (d.source.x + d.target.x) / 2 - 40) // Position the text in the middle of the link
        .attr('y', d => (d.source.y + d.target.y) / 2 - 10); // Position the text in the middle of the link
      });

      // Calculate the bounding box of all nodes
        const nodeBBox = svg.node().getBBox();

        // Calculate the scale to fit all nodes within the view
        const scale = Math.min(width / nodeBBox.width, height / nodeBBox.height);

        // Calculate the new translation to center the nodes within the view
        const centerX = nodeBBox.x + nodeBBox.width / 2;
        const centerY = nodeBBox.y + nodeBBox.height / 2;
        const translateX = width / 2 - centerX * scale;
        const translateY = height / 2 - centerY * scale;

        // Apply the zoom transformation to fit all nodes within the view
        svg.transition()
        .duration(750)
        .call(d3.zoom().transform, d3.zoomIdentity.scale(scale).translate(translateX, translateY));


    function zoomed(event) {
        svg.attr('transform', event.transform);

        // // Get the extent of all nodes
        // const nodeExtent = d3.extent(data.node, d => [d.x, d.y]);

        // // Calculate the width and height of the node extent
        // const nodeWidth = nodeExtent[1][0] - nodeExtent[0][0];
        // const nodeHeight = nodeExtent[1][1] - nodeExtent[0][1];

        // // Calculate the center of the node extent
        // const nodeCenterX = (nodeExtent[0][0] + nodeExtent[1][0]) / 2;
        // const nodeCenterY = (nodeExtent[0][1] + nodeExtent[1][1]) / 2;

        // // Calculate the zoom scale to fit all nodes within the view
        // const zoomScale = Math.min(width / nodeWidth, height / nodeHeight);

        // // Calculate the new translation to center the nodes within the view
        // const newTranslate = [
        //     width / 2 - nodeCenterX * zoomScale,
        //     height / 2 - nodeCenterY * zoomScale,
        // ];

        // // Apply the zoom transformation to fit all nodes within the view
        // svg.call(d3.zoom().transform, d3.zoomIdentity.scale(zoomScale).translate(newTranslate[0], newTranslate[1]));
    }
    function drag(simulation) {
        function dragstarted(event) {
            if (!event.active) simulation.alphaTarget(0.3).restart();
            event.subject.fx = event.subject.x;
            event.subject.fy = event.subject.y;
        }

        function dragged(event) {
            event.subject.fx = event.x;
            event.subject.fy = event.y;
        }

        function dragended(event) {
            if (!event.active) simulation.alphaTarget(0);
            event.subject.fx = null;
            event.subject.fy = null;
        }

        return d3.drag()
            .on('start', dragstarted)
            .on('drag', dragged)
            .on('end', dragended);
    }


};

// Entry point to load and render the data
const init = async () => {
  const data = await fetchData();
  if (data) {
    createGraph(data.data);
  } else {
    // Handle error or show a message that the data could not be fetched
  }
};

init();
